#include "Box.h"
#include "Vertex.h"

namespace D3D10Utils
{
	Box::Box()
		: md3dDevice(0)
		, mPositionsVertexBuffer(0)
		, mColorsVertexBuffer(0)
		, mIndexBuffer(0)
		, mNumVertices(0)
		, mNumFaces(0)
	{
	}
 
	Box::~Box()
	{
		ReleaseCOM(mPositionsVertexBuffer);
		ReleaseCOM(mColorsVertexBuffer);
		ReleaseCOM(mIndexBuffer);
	}

	void Box::init(ID3D10Device * const device, const float scale)
	{
		md3dDevice = device;
 
		mNumVertices = 8;
		mNumFaces    = 12; // 2 per quad

		// Create vertex buffers
		D3DXVECTOR3 verticesPositions[] =
    	{
			D3DXVECTOR3(-1.0f, -1.0f, -1.0f),
			D3DXVECTOR3(-1.0f, +1.0f, -1.0f),
			D3DXVECTOR3(+1.0f, +1.0f, -1.0f),
			D3DXVECTOR3(+1.0f, -1.0f, -1.0f),
			D3DXVECTOR3(-1.0f, -1.0f, +1.0f),
			D3DXVECTOR3(-1.0f, +1.0f, +1.0f),
			D3DXVECTOR3(+1.0f, +1.0f, +1.0f),
			D3DXVECTOR3(+1.0f, -1.0f, +1.0f)
    	};

		D3DXCOLOR verticesColors[] =
    	{
			WHITE,
			BLACK,
			RED,
			GREEN,
			BLUE,
			YELLOW,
			CYAN,
			MAGENTA
    	};

		// Scale the box.
		for(DWORD i = 0; i < mNumVertices; ++i)
			verticesPositions[i] *= scale;

		// Description of the vertex buffer for positions
    	D3D10_BUFFER_DESC vertexBufferDescription;
    	vertexBufferDescription.ByteWidth = sizeof(D3DXVECTOR3) * mNumVertices;

    	// A resource that can only be read by the GPU. 
    	// It cannot be written by the GPU, and cannot be accessed at all by the CPU. 
    	// This type of resource must be initialized when it is created, 
		// since it cannot be changed after creation.
    	vertexBufferDescription.Usage = D3D10_USAGE_IMMUTABLE; 

    	// Bind a buffer as a vertex buffer to the input-assembler stage.
    	vertexBufferDescription.BindFlags = D3D10_BIND_VERTEX_BUFFER; 
    	vertexBufferDescription.CPUAccessFlags = 0; // No CPU access necessary.
    	vertexBufferDescription.MiscFlags = 0; 	

		// Specifies data for initializing a subresource.
   	 	D3D10_SUBRESOURCE_DATA vertexBufferData;
    	vertexBufferData.pSysMem = verticesPositions;

    	ErrorHandler(md3dDevice->CreateBuffer(&vertexBufferDescription, &vertexBufferData,
			&mPositionsVertexBuffer));

		// Description of the vertex buffer for colors
    	vertexBufferDescription.ByteWidth = sizeof(D3DXCOLOR) * mNumVertices;

    	// A resource that can only be read by the GPU. 
    	// It cannot be written by the GPU, and cannot be accessed at all by the CPU. 
    	// This type of resource must be initialized when it is created, 
		// since it cannot be changed after creation.
    	vertexBufferDescription.Usage = D3D10_USAGE_IMMUTABLE; 

    	// Bind a buffer as a vertex buffer to the input-assembler stage.
    	vertexBufferDescription.BindFlags = D3D10_BIND_VERTEX_BUFFER; 
    	vertexBufferDescription.CPUAccessFlags = 0; // No CPU access necessary.
    	vertexBufferDescription.MiscFlags = 0; 	

		// Specifies data for initializing a subresource.
    	vertexBufferData.pSysMem = verticesColors;

    	ErrorHandler(md3dDevice->CreateBuffer(&vertexBufferDescription, &vertexBufferData,
			&mColorsVertexBuffer));

		// Create the index buffer
		DWORD indices[] = {
			// front face
			0, 1, 2,
			0, 2, 3,

			// back face
			4, 6, 5,
			4, 7, 6,

			// left face
			4, 5, 1,
			4, 1, 0,

			// right face
			3, 2, 6,
			3, 6, 7,

			// top face
			1, 5, 6,
			1, 6, 2,

			// bottom face
			4, 0, 3, 
			4, 3, 7
		};

		// Description of the index buffer.
		D3D10_BUFFER_DESC indexBufferDescription;
		indexBufferDescription.ByteWidth = sizeof(DWORD) * mNumFaces * 3;
		
    	// A resource that can only be read by the GPU. 
    	// It cannot be written by the GPU, and cannot be accessed at all by the CPU. 
    	// This type of resource must be initialized when it is created, 
		// since it cannot be changed after creation.
    	indexBufferDescription.Usage = D3D10_USAGE_IMMUTABLE;
	
    	// Bind a buffer as a index buffer to the input-assembler stage.
    	indexBufferDescription.BindFlags = D3D10_BIND_INDEX_BUFFER;
    	indexBufferDescription.CPUAccessFlags = 0; // No CPU access necessary.
    	indexBufferDescription.MiscFlags = 0;

    	D3D10_SUBRESOURCE_DATA indexBufferData;
    	indexBufferData.pSysMem = indices;

    	ErrorHandler(md3dDevice->CreateBuffer(&indexBufferDescription, &indexBufferData, &mIndexBuffer));
	}

	void Box::draw()
	{
		ID3D10Buffer * const buffers[] = {mPositionsVertexBuffer, mColorsVertexBuffer};
		const UINT strides[] = {sizeof(D3DXVECTOR3), sizeof(D3DXCOLOR)};
		const UINT offsets[] = {0, 0};
    	
		md3dDevice->IASetVertexBuffers(0, 2, buffers, strides, offsets);
		md3dDevice->IASetIndexBuffer(mIndexBuffer, DXGI_FORMAT_R32_UINT, 0);		
		md3dDevice->DrawIndexed(mNumFaces * 3, 0, 0);
	}
}
